#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
 * https://blog.csdn.net/chen0810618209/article/details/131185192
 */
static const uint8_t crc8_table[256] = {
    0x00, 0x1D, 0x3A, 0x27, 0x74, 0x69, 0x4E, 0x53, 0xE8, 0xF5, 0xD2, 0xCF, 0x9C, 0x81, 0xA6, 0xBB, 0xCD, 0xD0, 0xF7, 0xEA, 0xB9, 0xA4, 0x83, 0x9E, 0x25, 0x38,
    0x1F, 0x02, 0x51, 0x4C, 0x6B, 0x76, 0x87, 0x9A, 0xBD, 0xA0, 0xF3, 0xEE, 0xC9, 0xD4, 0x6F, 0x72, 0x55, 0x48, 0x1B, 0x06, 0x21, 0x3C, 0x4A, 0x57, 0x70, 0x6D,
    0x3E, 0x23, 0x04, 0x19, 0xA2, 0xBF, 0x98, 0x85, 0xD6, 0xCB, 0xEC, 0xF1, 0x13, 0x0E, 0x29, 0x34, 0x67, 0x7A, 0x5D, 0x40, 0xFB, 0xE6, 0xC1, 0xDC, 0x8F, 0x92,
    0xB5, 0xA8, 0xDE, 0xC3, 0xE4, 0xF9, 0xAA, 0xB7, 0x90, 0x8D, 0x36, 0x2B, 0x0C, 0x11, 0x42, 0x5F, 0x78, 0x65, 0x94, 0x89, 0xAE, 0xB3, 0xE0, 0xFD, 0xDA, 0xC7,
    0x7C, 0x61, 0x46, 0x5B, 0x08, 0x15, 0x32, 0x2F, 0x59, 0x44, 0x63, 0x7E, 0x2D, 0x30, 0x17, 0x0A, 0xB1, 0xAC, 0x8B, 0x96, 0xC5, 0xD8, 0xFF, 0xE2, 0x26, 0x3B,
    0x1C, 0x01, 0x52, 0x4F, 0x68, 0x75, 0xCE, 0xD3, 0xF4, 0xE9, 0xBA, 0xA7, 0x80, 0x9D, 0xEB, 0xF6, 0xD1, 0xCC, 0x9F, 0x82, 0xA5, 0xB8, 0x03, 0x1E, 0x39, 0x24,
    0x77, 0x6A, 0x4D, 0x50, 0xA1, 0xBC, 0x9B, 0x86, 0xD5, 0xC8, 0xEF, 0xF2, 0x49, 0x54, 0x73, 0x6E, 0x3D, 0x20, 0x07, 0x1A, 0x6C, 0x71, 0x56, 0x4B, 0x18, 0x05,
    0x22, 0x3F, 0x84, 0x99, 0xBE, 0xA3, 0xF0, 0xED, 0xCA, 0xD7, 0x35, 0x28, 0x0F, 0x12, 0x41, 0x5C, 0x7B, 0x66, 0xDD, 0xC0, 0xE7, 0xFA, 0xA9, 0xB4, 0x93, 0x8E,
    0xF8, 0xE5, 0xC2, 0xDF, 0x8C, 0x91, 0xB6, 0xAB, 0x10, 0x0D, 0x2A, 0x37, 0x64, 0x79, 0x5E, 0x43, 0xB2, 0xAF, 0x88, 0x95, 0xC6, 0xDB, 0xFC, 0xE1, 0x5A, 0x47,
    0x60, 0x7D, 0x2E, 0x33, 0x14, 0x09, 0x7F, 0x62, 0x45, 0x58, 0x0B, 0x16, 0x31, 0x2C, 0x97, 0x8A, 0xAD, 0xB0, 0xE3, 0xFE, 0xD9, 0xC4};

/*Function Name：CRC8_SAEJ1850_LOOKUP;
        CRC8_SAEJ1850 lookup table
        parameter: uint8_t[] buf;
                   uint8_t len;
        return:    uint8_t
        */
uint8_t CRC8_SAEJ1850_LOOKUP(uint8_t* buf, uint8_t len) {
  uint8_t i;
  uint8_t u8_crc8;
  u8_crc8 = 0xFF;

  for (i = 0; i < len; i++) {
    u8_crc8 ^= buf[i];
    u8_crc8 = crc8_table[u8_crc8];
    // printf("data[%d]=0X%x\n", i, buf[i]);
  }
  u8_crc8 ^= (uint8_t)0xFF;
  return u8_crc8;
}
/*
 * https://blog.csdn.net/sun520up/article/details/100515537
 */
// uint8_t CRC8(uint8_t* u8_data, uint8_t u8_len) {
//   uint8_t i, j;
//   uint8_t u8_crc8;
//   uint8_t u8_poly;

//   u8_crc8 = 0xFF;
//   u8_poly = 0x1D;

//   for (i = 0; i < u8_len; i++) {
//     u8_crc8 ^= u8_data[i];

//     for (j = 0; j < 8; j++) {
//       if (u8_crc8 & 0x80) {
//         u8_crc8 = (u8_crc8 << 1) ^ u8_poly;
//       } else {
//         u8_crc8 <<= 1;
//       }
//     }
//   }

//   u8_crc8 ^= (uint8_t)0xFF;
//   return u8_crc8;
// }

// /* ECHO_CRC */
// #define CRC_TABLE_NUMS    (256U)
// #define CRC_INIT_0        (0U)
// #define CRC_8_START_VALUE (0xFFU)
// #define CRC_XOR_VALUE_8   (0xFFU)
// #define NULL_PTR          ((void*)0)

// /* byte deal with. */
// #define E2E_HIGH_NIBBLE (0xF0U)
// #define E2E_LOW_NIBBLE  (0x0FU)
// #define E2E_HIGH_BYTE   (0xFF00U)
// #define E2E_FULL_BYTE   (0xFFU)
// #define E2E_FULL_2BYTE  (0xFFFFU)
// #define E2E_FULL_4BYTE  (0xFFFFFFFFU)

// static uint8_t Crc8_Table[CRC_TABLE_NUMS] = {
//     0x00U, 0x1DU, 0x3AU, 0x27U, 0x74U, 0x69U, 0x4EU, 0x53U, 0xE8U, 0xF5U, 0xD2U, 0xCFU, 0x9CU, 0x81U, 0xA6U, 0xBBU, 0xCDU, 0xD0U, 0xF7U, 0xEAU, 0xB9U, 0xA4U,
//     0x83U, 0x9EU, 0x25U, 0x38U, 0x1FU, 0x02U, 0x51U, 0x4CU, 0x6BU, 0x76U, 0x87U, 0x9AU, 0xBDU, 0xA0U, 0xF3U, 0xEEU, 0xC9U, 0xD4U, 0x6FU, 0x72U, 0x55U, 0x48U,
//     0x1BU, 0x06U, 0x21U, 0x3CU, 0x4AU, 0x57U, 0x70U, 0x6DU, 0x3EU, 0x23U, 0x04U, 0x19U, 0xA2U, 0xBFU, 0x98U, 0x85U, 0xD6U, 0xCBU, 0xECU, 0xF1U, 0x13U, 0x0EU,
//     0x29U, 0x34U, 0x67U, 0x7AU, 0x5DU, 0x40U, 0xFBU, 0xE6U, 0xC1U, 0xDCU, 0x8FU, 0x92U, 0xB5U, 0xA8U, 0xDEU, 0xC3U, 0xE4U, 0xF9U, 0xAAU, 0xB7U, 0x90U, 0x8DU,
//     0x36U, 0x2BU, 0x0CU, 0x11U, 0x42U, 0x5FU, 0x78U, 0x65U, 0x94U, 0x89U, 0xAEU, 0xB3U, 0xE0U, 0xFDU, 0xDAU, 0xC7U, 0x7CU, 0x61U, 0x46U, 0x5BU, 0x08U, 0x15U,
//     0x32U, 0x2FU, 0x59U, 0x44U, 0x63U, 0x7EU, 0x2DU, 0x30U, 0x17U, 0x0AU, 0xB1U, 0xACU, 0x8BU, 0x96U, 0xC5U, 0xD8U, 0xFFU, 0xE2U, 0x26U, 0x3BU, 0x1CU, 0x01U,
//     0x52U, 0x4FU, 0x68U, 0x75U, 0xCEU, 0xD3U, 0xF4U, 0xE9U, 0xBAU, 0xA7U, 0x80U, 0x9DU, 0xEBU, 0xF6U, 0xD1U, 0xCCU, 0x9FU, 0x82U, 0xA5U, 0xB8U, 0x03U, 0x1EU,
//     0x39U, 0x24U, 0x77U, 0x6AU, 0x4DU, 0x50U, 0xA1U, 0xBCU, 0x9BU, 0x86U, 0xD5U, 0xC8U, 0xEFU, 0xF2U, 0x49U, 0x54U, 0x73U, 0x6EU, 0x3DU, 0x20U, 0x07U, 0x1AU,
//     0x6CU, 0x71U, 0x56U, 0x4BU, 0x18U, 0x05U, 0x22U, 0x3FU, 0x84U, 0x99U, 0xBEU, 0xA3U, 0xF0U, 0xEDU, 0xCAU, 0xD7U, 0x35U, 0x28U, 0x0FU, 0x12U, 0x41U, 0x5CU,
//     0x7BU, 0x66U, 0xDDU, 0xC0U, 0xE7U, 0xFAU, 0xA9U, 0xB4U, 0x93U, 0x8EU, 0xF8U, 0xE5U, 0xC2U, 0xDFU, 0x8CU, 0x91U, 0xB6U, 0xABU, 0x10U, 0x0DU, 0x2AU, 0x37U,
//     0x64U, 0x79U, 0x5EU, 0x43U, 0xB2U, 0xAFU, 0x88U, 0x95U, 0xC6U, 0xDBU, 0xFCU, 0xE1U, 0x5AU, 0x47U, 0x60U, 0x7DU, 0x2EU, 0x33U, 0x14U, 0x09U, 0x7FU, 0x62U,
//     0x45U, 0x58U, 0x0BU, 0x16U, 0x31U, 0x2CU, 0x97U, 0x8AU, 0xADU, 0xB0U, 0xE3U, 0xFEU, 0xD9U, 0xC4U};

// uint8_t Crc_CalculateCRC8(uint8_t* Crc_DataPtr, uint32_t Crc_Length, uint8_t Crc_StartValue8, bool Crc_IsFirstCall) {
//   bool     crc8IsFirstCall;
//   uint8_t  crc8ChkSum;
//   uint8_t  crc8StartValue8;
//   uint32_t crc8Idx;
//   uint32_t crc8Length;

//   crc8Length      = Crc_Length;        /* Copy Crc_Length to local. */
//   crc8StartValue8 = Crc_StartValue8;   /* Copy Crc_StartValue8 to local. */
//   crc8IsFirstCall = Crc_IsFirstCall;   /* Copy Crc_IsFirstCall to local. */
//   crc8ChkSum      = CRC_8_START_VALUE; /* Initial value: 0xFF. */

//   if (Crc_DataPtr != NULL_PTR) /* Pointer parameter is a null pointer. */
//   {
//     /* The algorithm is called for the first time. */
//     if (true == crc8IsFirstCall) {
//       /* The value of Crc8_ChkSum is 0xFF. */
//       crc8ChkSum = CRC_8_START_VALUE;
//     } else {
//       /* The value of Crc8_ChkSum is the last calculation result of
//          Crc8_ChkSum. */
//       crc8ChkSum = ~crc8StartValue8;
//     }

//     for (crc8Idx = CRC_INIT_0; crc8Idx < crc8Length; crc8Idx++) {
//       /* XOR operations on bytes of the entire data block. */
//       crc8ChkSum = Crc8_Table[crc8ChkSum ^ Crc_DataPtr[crc8Idx]];
//     }
//     /* Calculating the value of Crc8_ChkSum. */
//     crc8ChkSum ^= (uint8_t)CRC_XOR_VALUE_8;
//   }
//   return (crc8ChkSum);
// }

static void buffer_dump(uint8_t* buf, uint8_t len) {
  for (uint8_t i = 0; i < len; i++) {
    printf("0X%x ", buf[i]);
  }
  printf("\n");
}

static uint8_t CAN_CRC8_CALC(uint16_t CAN_ID, uint8_t* buf) {
  uint8_t can_crc[9]   = {0};
  uint8_t r_crc_buffer = 0;

  can_crc[0] = ((CAN_ID >> 8) & 0XFF);
  can_crc[1] = ((CAN_ID >> 0) & 0XFF);
  memcpy(&can_crc[2], buf, 7);

  // buffer_dump(can_crc, 9);

  r_crc_buffer = CRC8_SAEJ1850_LOOKUP(can_crc, 9);
  return r_crc_buffer;
}

// 自动偏移的代码
#define buf_len_max (8U)
static uint8_t CAN_CRC8_CALC_data_del_crc(uint16_t CAN_ID, uint8_t* buf, uint8_t buf_len, uint8_t crc_index) {
  /* crc_index:CRC在DATA数据中的索引，从0开始0-7 */
  /* max_buf_len = 8
   * max_crc_index = 7
   */
  uint8_t can_crc[12]     = {0};
  uint8_t can_crc_cal[12] = {0};
  uint8_t r_crc_buffer    = 0;

  // can_crc[0] = ((CAN_ID >> 8) & 0XFF);
  // can_crc[1] = ((CAN_ID >> 0) & 0XFF);
  // memcpy(can_crc, buf, buf_len);
  // buffer_dump(can_crc, 12);

  for (uint8_t i = 0; i < buf_len; i++) {
    can_crc[i] = buf[i];
  }

  can_crc_cal[0] = ((CAN_ID >> 8) & 0XFF);
  can_crc_cal[1] = ((CAN_ID >> 0) & 0XFF);
  if (crc_index != (buf_len - 1)) {  // 判断CRC的索引是否是buf的最后一个字节
    for (uint8_t i = 0; i < (buf_len - crc_index - 1); i++) {
      can_crc[crc_index + i] = can_crc[crc_index + 1 + i];
    }

    // memcpy(&can_crc[crc_index], &can_crc[crc_index + 1], buf_len - crc_index - 1);
  }
  for (uint8_t i = 0; i < (buf_len - 1); i++) {
    can_crc_cal[2 + i] = can_crc[i];
  }
  // memcpy(&can_crc_cal[2], can_crc, buf_len - 1);

  // buffer_dump(can_crc_cal, 12);

  r_crc_buffer = CRC8_SAEJ1850_LOOKUP(can_crc_cal, 9);  // 9是除了ID2Byte+DATA7Byte(出去CRC的Byte)
  return r_crc_buffer;
}

#define crc_buffer_len (7U)
int main() {
  uint8_t crc_buffer1[crc_buffer_len] = {0X00, 0X01, 0X10, 0X77, 0XF8, 0X00, 0X15};
  // uint8_t crc_buffer2[crc_buffer_len] = {0X01, 0X00, 0X10, 0X77, 0XF8, 0X00, 0X15};
  // uint8_t crc_buffer3[crc_buffer_len] = {0X01, 0X10, 0X00, 0X77, 0XF8, 0X00, 0X15};
  // uint8_t crc_buffer4[crc_buffer_len] = {0X01, 0X10, 0X77, 0X00, 0XF8, 0X00, 0X15};
  // uint8_t crc_buffer5[crc_buffer_len] = {0X01, 0X10, 0X77, 0XF8, 0X00, 0X00, 0X15};
  // uint8_t crc_buffer6[crc_buffer_len] = {0X01, 0X10, 0X77, 0XF8, 0X00, 0X00, 0X15};
  // uint8_t crc_buffer7[crc_buffer_len] = {0X01, 0X10, 0X77, 0XF8, 0X00, 0X15, 0X00};

  uint8_t crc_buffer8[6]  = {0XA1, 0X00, 0X10, 0X77, 0XF8, 0X00};
  uint8_t crc_buffer9[5]  = {0XA2, 0X00, 0X00, 0X77, 0XF8};
  uint8_t crc_buffer10[4] = {0XA3, 0X00, 0X77, 0X00};
  uint8_t crc_buffer11[3] = {0XA4, 0X00, 0X77};
  uint8_t crc_buffer12[2] = {0XA5, 0X00};
  uint8_t crc_buffer13[6] = {0X00, 0XFF, 0X80, 0X50, 0X60, 0X14};
  uint8_t crc_pri         = 0;

  // crc_pri = CRC8_SAEJ1850_LOOKUP(crc_buffer, 7);
  // printf("crc_pri:0X%x\n", crc_pri);

  // crc_pri = CRC8(crc_buffer, 7);
  // printf("CRC8:0X%x\n", crc_pri);

  // crc_pri = Crc_CalculateCRC8(crc_buffer, 7, E2E_FULL_BYTE, false);
  // printf("ECHO_CRC8:0X%x\n", crc_pri);

  // crc_pri = CAN_CRC8_CALC_data_del_crc(0X45E, crc_buffer1, crc_buffer_len, 0);
  // printf("CAN_CRC8:0X%x\n", crc_pri);
  // crc_pri = CAN_CRC8_CALC_data_del_crc(0X45E, crc_buffer2, crc_buffer_len, 1);
  // printf("CAN_CRC8:0X%x\n", crc_pri);
  // crc_pri = CAN_CRC8_CALC_data_del_crc(0X45E, crc_buffer3, crc_buffer_len, 2);
  // printf("CAN_CRC8:0X%x\n", crc_pri);
  // crc_pri = CAN_CRC8_CALC_data_del_crc(0X45E, crc_buffer4, crc_buffer_len, 3);
  // printf("CAN_CRC8:0X%x\n", crc_pri);
  // crc_pri = CAN_CRC8_CALC_data_del_crc(0X45E, crc_buffer5, crc_buffer_len, 4);
  // printf("CAN_CRC8:0X%x\n", crc_pri);
  // crc_pri = CAN_CRC8_CALC_data_del_crc(0X45E, crc_buffer6, crc_buffer_len, 5);
  // printf("CAN_CRC8:0X%x\n", crc_pri);
  // crc_pri = CAN_CRC8_CALC_data_del_crc(0X45E, crc_buffer7, crc_buffer_len, 6);
  // printf("CAN_CRC8:0X%x\n", crc_pri);

  // crc_pri = CAN_CRC8_CALC_data_del_crc(0X45E, crc_buffer8, 6, 1);
  // printf("CAN_CRC8:0X%x\n", crc_pri);
  // crc_pri = CAN_CRC8_CALC_data_del_crc(0X45E, crc_buffer9, 5, 1);
  // printf("CAN_CRC8:0X%x\n", crc_pri);
  // crc_pri = CAN_CRC8_CALC_data_del_crc(0X45E, crc_buffer10, 4, 1);
  // printf("CAN_CRC8:0X%x\n", crc_pri);
  // crc_pri = CAN_CRC8_CALC_data_del_crc(0X45E, crc_buffer11, 3, 1);
  // printf("CAN_CRC8:0X%x\n", crc_pri);
  // crc_pri = CAN_CRC8_CALC_data_del_crc(0X45E, crc_buffer12, 2, 1);
  // printf("CAN_CRC8:0X%x\n", crc_pri);

  crc_pri = CAN_CRC8_CALC_data_del_crc(0X070, crc_buffer13, 6, 0);
  printf("CAN_CRC8:0X%x\n", crc_pri);

  return 0;
}
